/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
#ifndef GIMI_UTILS_H
#define GIMI_UTILS_H

#include <string>
#include <list>
#include <vector>
#include <set>
#include <map>

#include <cassert>
#include <inttypes.h>
#include <limits.h>

// Utils
#include "gimutils.h"
#include "ownutils.h"
#include "owndebug.h"
//#include <stdlib.h>

#include "bitestream.h"

#include "gimiprotocoltypes.h"
#include "datatypedefinitions.h"
#include "activestatus.h"

#include "gimiversion.h"

/*** Defines for external use ***/
// These are return values used by GIMI
#define GIMI_OK                               0
#define GIMI_ERROR                            -1
#define GIMI_TIMEOUT                          -2
#define GIMI_NOCONNECTION                     -3
#define GIMI_INTERRUPT                        -4
#define GIMI_NOSUBSCRIBERS                    -5
#define GIMI_INVALIDTYPE                      -6
#define GIMI_NOMSGS                           -7
#define GIMI_INVALIDCLIENT                    -8
#define GIMI_EMPTY                            -9
#define GIMI_INVALIDNAME                      -10
#define GIMI_CONGESTED                        -11

// Errors for socket-system
#define GIMI_TCPSTACK                         -101
#define GIMI_CREATESOCKETERROR                -102
#define GIMI_RESOLVEHOSTERROR                 -103
#define GIMI_CONNECTIONERROR                  -104
#define GIMI_SOCKETREADERROR                  -105
#define GIMI_INVALIDHUBDATA                   -106

// Defines for servicetypes.
#define GIMI_SERVICETYPE_PROVIDED             1
#define GIMI_SERVICETYPE_DESCRIPTION          2
#define GIMI_SERVICETYPE_ACCEPTED             3

// Default size for a messagequeue. When maximum size is reached, old
// messages are dropped when a new arrives
#define GIMI_DEFAULTQUEUESIZE                 10000

#define GIMI_IGNOREMINORTYPE                  -1
#define GIMI_IGNOREMAJORTYPE                  -1
#define GIMI_INVALIDREPLYVALUE                -666
/*** ************************ ***/

/*** Defines for internal use ***/
// Bufferid for the default-queue.
#define GIMI_DEFAULTBUFFERID                  0

// Upkeep-loop run interval in milliseconds.
#define GIMI_UPKEEPINTERVAL                   250

// Interval between reconnect attempts in milliseconds.
#define GIMI_RECONNECTINTERVAL                5000

// Minimum and maximum amount of tags for different gimi-message types.
#define GIMI_MSG_TAGN_MIN                     6
#define GIMI_MSG_TAGN_MAX                     7

#define GIMI_MSG_TAGN_DATA_MIN                6
#define GIMI_MSG_TAGN_DATA_MAX                7

#define GIMI_MSG_TAGN_CONTROL_MIN             6
#define GIMI_MSG_TAGN_CONTROL_MAX             7

//// GIMITAG_ values are in bitestream/tagvalues.h
//// Values for GIM_PROTOCOL_GIMI_MESSAGE
#define GIMI_PROTOCOL_DATA                    1
#define GIMI_PROTOCOL_DATA_SUBSCRIBED         2
#define GIMI_PROTOCOL_CONTROL_DATA            11
#define GIMI_PROTOCOL_CONTROL_DATA_SUBSCRIBED 12
#define GIMI_PROTOCOL_CONTROL_GENERIC         13
#define GIMI_PROTOCOL_CONTROL_SERVICES        14

//// Values for GIMITAG_ACTION (a bit-flag, multiple commands can be used at the same time.
// When flag is set, send a reply about commands success.
#define GIMI_ACT_REQUESTREPLY                 1
// When flag is set, message is considered a command (and not a reply)
#define GIMI_ACT_DOCOMMAND                    2

//// Values for GIMITAG_COMMAND
#define GIMI_CMD_PING                         1
// Service commands
#define GIMI_CMD_SUBSCRIBE                    2
#define GIMI_CMD_UNSUBSCRIBE                  3
#define GIMI_CMD_LIST                         4
// Control commands
#define GIMI_CMD_SETDEBUGLEVEL                5

// Subscribed data. Refresh subscriptions.
#define GIMI_CMD_KEEPALIVE                    6

//// Values for GIMITAG_REPLY
#define GIMI_REPLY_OK                         GIMI_OK
#define GIMI_REPLY_INVALIDTYPE                GIMI_INVALIDTYPE
#define GIMI_REPLY_INVALIDCLIENT              GIMI_INVALIDCLIENT
#define GIMI_REPLY_ERROR                      GIMI_ERROR

namespace gimi {

static gimi::DataTypeDefinitions datatypeDefinitions; ///< Contains names and descriptions for all datatypes.
  
/**
 * Returns string corresponding to given error code.
 * 
 * \return empty string if error code was invalid.
 */
std::string getGimiErrorString(const int errorNo);

/**
 * \struct GIMIService
 * Container for information about a single service or description.
 */
struct GIMIService {
  GIMIService();
  GIMIService(const int cId,
              const std::string cName,
              const int sType,
              const int majorSId,
              const int minorSId,
              const std::string sDescr = "",
              const std::string sLoc = "",
              const int gVersion = 0,
              const int gbuild = 0,
              const int cVersion = 0,
              const int cBuild = 0);
  
  std::string getShortServiceTypeString() const;
  std::string getServiceTypeString() const;
  
  int clientId;
  std::string clientName;
  int serviceType; ///< Tells if this is a pure description, service or accepted type.
  int majorServiceId;
  int minorServiceId;
  std::string serviceDescription;
  std::string serviceLocation;
  gim::version gimiVersion; ///< If \ref serviceType is description, contains
                            ///< version of client's GIMI.
  gim::version clientVersion; ///< If \ref serviceType is description, contains
                              ///< client's version-information.
};

/**
 * \struct GIMIRedirection
 * Contains information about a single redirection.
 */
struct GIMIRedirection {
  GIMIRedirection(const unsigned int targetQId,
                  const int majorSId = -1,
                  const int minorSId = -1,
                  const int sendId = -1);
  
  unsigned int targetQueueId;
  int majorServiceId;
  int minorServiceId;
  int senderId;
};

typedef std::vector<std::string> t_stringVector;
typedef t_stringVector::iterator t_stringVectorIterator;
typedef t_stringVector::const_iterator t_stringVectorConstIterator;

typedef std::vector< uint32_t > t_uidList;
typedef t_uidList::iterator t_uidListIterator;
typedef t_uidList::const_iterator t_uidListConstIterator;

typedef std::vector< int > t_intVector;
typedef t_intVector::iterator t_intVectorIterator;
typedef t_intVector::const_iterator t_intVectorConstIterator;

typedef std::vector< uint32_t > t_clientIdList;

// Information of a client, int clientid, string clientname
typedef std::pair< int, std::string > t_clientPair;

typedef std::vector< t_clientPair > t_clientList;
typedef t_clientList::iterator t_clientListIterator;
typedef t_clientList::const_iterator t_clientListConstIterator;

typedef std::vector< GIMIService > t_serviceList;
typedef t_serviceList::iterator t_serviceListIterator;
typedef t_serviceList::const_iterator t_serviceListConstIterator;

typedef std::vector < GIMIRedirection > t_redirectionList;
typedef t_redirectionList::iterator t_redirectionListIterator;
typedef t_redirectionList::const_iterator t_redirectionListConstIterator;

typedef std::vector< uint8_t > t_binaryArray;

// New style types. (Or _my_ style types :)
 typedef std::list< t_serviceList > TServiceListArray;
 typedef std::map<uint32_t, TServiceListArray > TServiceListBundleArray;


  
} // end namespace gimi

#endif // GIMI_UTILS_H
